/**
 * 递归复用遍历
 * 需要使用推断infer,因此需要手动造一个没啥大用处的条件类型extends.
 */
/**
 * 实操1
 * 将字面量类型拆成联合类型
 */
type A = "12345";
type Split<T extends string> = T extends `${infer One}${infer Rest}`
  ? One | Split<Rest>
  : never;

type ASplit = Split<A>;

/**
 * 实操2
 * 将数组类型进行反转
 */
type B = [1, 2, 3, 4, 5]; // 经过reverse变成[5,4,3,2,1]
type Reverse<T extends any[]> = T extends [infer One, ...infer Rest]
  ? [...Reverse<Rest>, One]
  : T; // 为什么这里是T？而不是never; 最后异步是5,4,3,2,1 直接返回就行
type BReverse = Reverse<B>;

/**
 * 实操3
 * 编写类型工具。获取一个字符串字面量类型的长度
 */
type C = "12345678910";
type Str2Arr<T extends string> = T extends `${infer One}${infer Rest}`
  ? [One, ...Str2Arr<Rest>]
  : [];
type GetStrLength<T extends string> = Str2Arr<T>["length"];
type CLength = GetStrLength<C>;

// 对实操2上面进行优化
type GetStrLength2<
  S extends string,
  T extends any[] = []
> = S extends `${infer F}${infer R}`
  ? GetStrLength2<R, [...T, F]>
  : T["length"]; // 第二个参数[]在每次递归的时候产生一个新的数组，数组个数持续增大，到最后就是字符串对应的完整数组了，因此可以在判断中直接使用length;
type CCLength = GetStrLength2<C>;

// 同理，在reverse中也可以传入一个数组来记录反转的数据
type Reverse2<T extends any[], R extends any[] = []> = T extends [
  infer One,
  ...infer Rest
]
  ? Reverse2<Rest, [One, ...R]>
  : R; // 为什么这里是T？每次递归会拿到上一个的结果进行拼接，到数组末尾，如果遇到never,就无法再拼接有效的结果，导致整个结果变成never,导致整个递归链的结果都是never;
// 就像阶乘的最后一个是0 会导致结果是0 一样
type BReverse2 = Reverse<B>;

/**
 * 实操4
 * 实现映射类型深层级的Optional。
 */
type User = {
  name: string;
  info: {
    banji: string;
    zuowei: string;
  };
};
type Optional<T extends Record<string, any>> = T extends any
  ? {
      [K in keyof T]+?: T[K] extends Record<string, any>
        ? Optional<T[K]>
        : T[K];
    }
  : never;
type UserOptional = Optional<User>;

type SwapArr<T extends any[]> = T extends [infer A, ...infer R]
  ? [...SwapArr<R>, A]
  : [];
type AA = SwapArr<[1, 2, 3, 4, 5]>;

export {};
